﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace Tools.Framework
{
    public static class CheckIpRanges
    {
        /// <summary>
        /// 多范围指定
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="ranges"></param>
        /// <returns></returns>
        static bool TheIpIsRange(string ip, params string[] ranges)
        {
            bool tmpRes = false;
            foreach (var item in ranges)
            {
                if (TheIpIsRange(ip, item))
                {
                    tmpRes = true; break;
                }
            }

            return tmpRes;
        }
        /// <summary>
        /// 判断指定的IP是否在指定的IP范围内   这里只能指定一个范围
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="ranges"></param>
        /// <returns></returns>
        public static bool TheIpIsRange(string ip, string ranges)
        {
            bool result = false;

            int count;
            string start_ip, end_ip;
            //检测指定的IP范围 是否合法
            TryParseRanges(ranges, out count, out start_ip, out end_ip);//检测ip范围格式是否有效

            if (ip == "::1") ip = "127.0.0.1";

            try
            {
                IPAddress.Parse(ip);//判断指定要判断的IP是否合法
            }
            catch (Exception)
            {
                throw new ApplicationException("要检测的IP地址无效");
            }

            if (count == 1 && ip == start_ip) result = true;//如果指定的IP范围就是一个IP，那么直接匹配看是否相等
            else if (count == 2)//如果指定IP范围 是一个起始IP范围区间
            {
                byte[] start_ip_array = Get4Byte(start_ip);//将点分十进制 转换成 4个元素的字节数组
                byte[] end_ip_array = Get4Byte(end_ip);
                byte[] ip_array = Get4Byte(ip);

                bool tmpRes = true;
                for (int i = 0; i < 4; i++)
                {
                    //从左到右 依次比较 对应位置的 值的大小  ，一旦检测到不在对应的范围 那么说明IP不在指定的范围内 并将终止循环
                    if (ip_array[i] > end_ip_array[i] || ip_array[i] < start_ip_array[i])
                    {
                        tmpRes = false; break;
                    }
                }
                result = tmpRes;
            }




            return result;
        }

        /// <summary>
        /// 判断IP是否属于该IP段
        /// </summary>
        /// <param name="ip">需要检测的IP</param>
        /// <param name="startIp">开始IP</param>
        /// <param name="endIp">结束IP</param>
        /// <returns></returns>
        public static bool TheIpIsRange(string ip, string start_ip, string end_ip)
        {
            bool result = false;

            int count = 2;
            if (string.IsNullOrWhiteSpace(start_ip) || string.IsNullOrWhiteSpace(end_ip))
            {
                count = 1;
            }
            if (ip == "::1") ip = "127.0.0.1";

            try
            {
                IPAddress.Parse(ip);//判断指定要判断的IP是否合法
            }
            catch (Exception)
            {
                throw new ApplicationException("要检测的IP地址无效");
            }

            if (count == 1 && ip == start_ip) result = true;//如果指定的IP范围就是一个IP，那么直接匹配看是否相等
            else if (count == 2)//如果指定IP范围 是一个起始IP范围区间
            {
                byte[] start_ip_array = Get4Byte(start_ip);//将点分十进制 转换成 4个元素的字节数组
                byte[] end_ip_array = Get4Byte(end_ip);
                byte[] ip_array = Get4Byte(ip);

                bool tmpRes = true;
                for (int i = 0; i < 4; i++)
                {
                    //从左到右 依次比较 对应位置的 值的大小  ，一旦检测到不在对应的范围 那么说明IP不在指定的范围内 并将终止循环
                    if (ip_array[i] > end_ip_array[i] || ip_array[i] < start_ip_array[i])
                    {
                        tmpRes = false; break;
                    }
                }
                result = tmpRes;
            }




            return result;
        }

        //尝试解析IP范围  并获取闭区间的 起始IP   (包含)
        private static void TryParseRanges(string ranges, out int count, out string start_ip, out string end_ip)
        {
            string[] _r = ranges.Split('-');
            if (!(_r.Count() == 2 || _r.Count() == 1))
                throw new ApplicationException("IP范围指定格式不正确，可以指定一个IP，如果是一个范围请用“-”分隔");

            count = _r.Count();

            start_ip = _r[0];
            end_ip = "";
            try
            {
                IPAddress.Parse(_r[0]);
            }
            catch (Exception)
            {
                throw new ApplicationException("IP地址无效");
            }

            if (_r.Count() == 2)
            {
                end_ip = _r[1];
                try
                {
                    IPAddress.Parse(_r[1]);
                }
                catch (Exception)
                {
                    throw new ApplicationException("IP地址无效");
                }
            }
        }


        /// <summary>
        /// 将IP四组值 转换成byte型
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        static byte[] Get4Byte(string ip)
        {
            byte[] res = Array.ConvertAll<string, byte>(ip.Split('.'), s => Convert.ToByte(s));
            return res.ToArray();
        }
        /// <summary>
        /// IP转为LONG
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        public static long IP2Long(string ip)
        {

            string[] ipBytes;
            double num = 0;
            if (!string.IsNullOrEmpty(ip))
            {
                ipBytes = ip.Split('.');
                for (int i = ipBytes.Length - 1; i >= 0; i--)
                {
                    num += ((int.Parse(ipBytes[i]) % 256) * Math.Pow(256, (3 - i)));
                }
            }
            return (long)num;
        }
        /// <summary>
        /// 判断是否在范围
        /// </summary>
        /// <returns></returns>
        public static bool IsTrue()
        {
            long start = IP2Long("127.0.0.1");
            long end = IP2Long("127.0.0.255");
            long ipAddress = IP2Long("127.0.1.253");
            bool inRange = (ipAddress >= start && ipAddress <= end);
            if (inRange)
            {
                //IP Address fits within range!
            }
            return true;
        }

    }
}
